<style type="text/css">
#gallery-wrapper {
  position: relative;
  width: 95%;
  max-width: 95%;
  margin: 50px auto;
}

img.thumb {
  width: 100%;
  max-width: 100%;
  height: auto;
}

.white-panel {
  position: absolute;
  padding: 10px;
  border-radius: 5px;
  background: white;
  box-shadow: 0 1px 2px rgb(0 0 0 / 30%);
}

.white-panel h1 {
  font-size: 1em;
}

.white-panel h1 a {
  color: #a92733;
}

.white-panel:hover {
  margin-top: -5px;
  transition: all 0.3s ease-in-out;
  box-shadow: 1px 1px 10px rgb(0 0 0 / 50%);
}

*,
*::after,
*::before {
  box-sizing: border-box;
}

a {
  outline: none;
  color: #2fa0ec;
  text-decoration: none;
}

a:hover,
a:focus {
  color: #74777b;
}

.button-gap {
  margin-left: 10px;
}
</style>
<template>
  <div ref="myButton">
    <div id="targettop"> </div>
    <Row justify="space-between" :gutter="[10, 10]">
      <Col>
      <Upload :multiple="true" :show-upload-list="false" :before-upload="handleBeforeUpload" class="upload-list-inline">
        <Button type="primary" class="button-gap">
          <upload-outlined></upload-outlined>
          上传
        </Button>
      </Upload>
      <Button type="primary" class="button-gap" @click="addImgDirPost">
        添加文件目录
      </Button>
      <Button type="primary" class="button-gap" @click="addcolumn">
        缩小
      </Button>
      <Badge class="button-gap" :count="column" :number-style="{
        backgroundColor: '#fff',
        color: '#0960bd',
        boxShadow: '0 0 0 1px #0960bd inset',
      }" />
      <Button type="primary" class="button-gap" @click="removecolumn">
        放大
      </Button>
      <Button type="primary" class="button-gap" @click="flush">开始加载</Button>
      <Button type="primary" class="button-gap" @click="scrollToButton">到底部</Button>
      </Col>
    </Row>
    <Row>
      <Col>
      <Breadcrumb :style="{ padding: '10px 0px 0px 10px' }">
        <BreadcrumbItem>
          <a href="#" @click.prevent="jump('')">根目录</a>
        </BreadcrumbItem>
        <BreadcrumbItem v-for="(part, index) in urls" :key="part">
          <a href="#" @click.prevent="jumpurl(index)">{{ part }}</a>
        </BreadcrumbItem>
      </Breadcrumb>
      </Col>
    </Row>
    <List v-if="filedata && filedata.length > 0" :style="{ padding: '10px 0px 10px 20px' }"
      :grid="{ gutter: 16, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: 9 }" :data-source="filedata">
      <template #renderItem="{ item }">
        <Dropdown :trigger="['contextmenu']">
          <ListItem>
            <a v-on:click="jump(item.keypath)">
              <Tag v-text="item.name" color="blue" class="mb-2"></Tag>
            </a>
          </ListItem>
          <template #overlay>
            <Menu>
              <MenuItem key="1" @click="clickImgDir(item)">修改</MenuItem>
              <Popconfirm title="确定删除?" ok-text="确定" cancel-text="取消" @confirm="delImgDirPost(item)">
                <MenuItem key="2">删除</MenuItem>
              </Popconfirm>
            </Menu>
          </template>
        </Dropdown>
      </template>
    </List>
    <ImagePreviewGroup>
      <div ref="containerRef" :style="{
        padding: '0 60px',
        position: 'relative',
        height: containerHeight + 'px',
      }">
        <div v-for="item in data" :key="item.path" class="item" :style="{
          width: columnWidth + 'px',
          position: 'absolute',
          transitionDuration: '300ms',
        }">
          <Image :preview="{
            src: item.path,
          }" :src="item.thumbnail" alt="" :style="{
            borderRadius: '0.25rem',
            height: (columnWidth / item.width) * item.height + 'px',
          }" />
          <Dropdown :trigger="['contextmenu']">
            <Tag v-text="item.name" color="blue" class="mb-2"></Tag>
            <template #overlay>
              <Menu>
                <MenuItem key="1" @click="clickImg(item)">修改</MenuItem>
                <Popconfirm title="确定删除?" ok-text="确定" cancel-text="取消" @confirm="delImgPost(item)">
                  <MenuItem key="2">删除</MenuItem>
                </Popconfirm>
              </Menu>
            </template>
          </Dropdown>
        </div>
      </div>
    </ImagePreviewGroup>
    <div id="targetButton"> </div>
    <Affix :offset-bottom="10">
      <Button type="primary" @click="stopload()">停止加载</Button>
      <Button type="primary" @click="scrollToTop()" class="button-gap">回顶部</Button>
    </Affix>
  </div>
  <Modal @ok="submitImgDir(true)" @cancel="submitImgDir(false)" :title="imgdirTitle" v-model:open="openimgdir">
    <Form>
      <FormItem label="图片目录名称">
        <Input v-model:value="params.name" />
      </FormItem>
    </Form>
  </Modal>
  <Modal @ok="submitImg(true)" @cancel="submitImg(false)" :title="imgTitle" v-model:open="openimg">
    <Form>
      <FormItem label="图片名称">
        <Input v-model:value="params.name" />
      </FormItem>
    </Form>
  </Modal>

</template>
<script lang="ts" setup>
import { Api } from "../util/Api";
import { upload, get, post } from "../util/MyAxios";
import { showMessage } from "../util/Mes";
import {
  Row,
  Col,
  List,
  ListItem,
  Tag,
  Image,
  ImagePreviewGroup,
  Badge,
  Button,
  Breadcrumb,
  BreadcrumbItem,
  Upload,
  message,
  Dropdown,
  MenuItem,
  Menu,
  Modal,
  Form,
  FormItem,
  Input,
  Popconfirm,
  Affix,
} from "ant-design-vue";
import {
  UploadOutlined,
} from "@ant-design/icons-vue";
import { ref, unref, onMounted, onBeforeMount, nextTick, watch } from "vue";

interface FileItem {
  index: number;
  path: string;
  name: string;
  keypath: string;
  isfolder: boolean;
  ctime: Date;
  utime: Date;
  isimg: boolean;
  width: number;
  height: number;
  length: number;
  src: string;
  thumbnail: string;
}
// 请求api时附带参数
const params = ref({
  path: "",
  name: "",
  oldname: "",
  newname: "",
  currentPage: 1,
  pageSize: 1,
});

const filename = ref("");
const filedata = ref<FileItem[]>([]);
const imgdata = ref<FileItem[]>([]);
const data = ref<FileItem[]>([]);
const urls = ref<string[]>([]);

const column = ref(6);
const rowSpacing = ref(20);
const columnSpacing = ref(20);
const flushdata = ref(0);
//滚动容器
const myButton = ref(null);
const containerRef = ref(null);
// 容器总宽度
const containerWidth = ref(0);
// 容器总高度
const containerHeight = ref(0);
// 列宽 = (容器宽度 - 列间距 * (列数 - 1)) / 列数
const columnWidth = ref(0);
const containerLeft = ref(0);
const uploadpath = ref("");
const openimgdir = ref<boolean>(false);
const openimg = ref<boolean>(false);
//true 正在加载，等等再说，false 加载完成，可以加载
const loadstatus = ref<boolean>(false);
//是否要加载
const isLoad = ref<boolean>(false);
const imgdirTitle = ref("");
const imgTitle = ref("");

// 定义目标按钮的引用 
const targetButton = ref(null);
const targettop = ref(null);

// 滚动到目标按钮的方法
const scrollToButton = () => {
  nextTick(() => {
    if (targetButton.value) {
      targetButton.value.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  });
};

// 滚动到目标按钮的方法
const scrollToTop = () => {
  nextTick(() => {
    if (targettop.value) {
      targettop.value.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  });
};

const handleBeforeUpload = (file) => {
  const formData = new FormData();
  formData.append("file", file);
  // console.log(file);
  if (params.value.path) {
    formData.append("fileurl", params.value.path);
  }
  return upload(Api.Img_UploadImg, formData, {
    headers: {
      "Content-Type": "multipart/form-data",
    },
  })
    .then((response) => {
      message.info("已上传:" + response.data);
      loadmore();
      return false;
    })
    .catch((error) => {
      console.error(error);
      return false;
    });
};


// 计算容器宽度
const useContainerWidth = () => {
  containerWidth.value = containerRef.value!.clientWidth;
};
// 计算列宽
const useColumnWidth = () => {
  columnWidth.value =
    (containerWidth.value - columnSpacing.value * (column.value - 1)) /
    column.value;
};
// 获取最小高度
const getMinHeight = (arr: number[]) => {
  return Math.min(...arr);
};
// 获取最小高度的索引
const getMinHeightIndex = (arr: number[]) => {
  return arr.indexOf(getMinHeight(arr));
};

// 获取所有图片的高度
const itemHeights = ref<number[]>([]);
const useItemHeight = () => {
  const allItems = document.querySelectorAll<HTMLElement>(".item");
  itemHeights.value = Array.from(allItems).map((item) => item.clientHeight); // {index:height}
};

const columnHeights = ref(Array(column.value).fill(0));

const getItemLeft = () => {
  const column = getMinHeightIndex(columnHeights.value);
  return (
    (columnWidth.value + columnSpacing.value) * column + containerLeft.value
  );
};

const getItemTop = () => {
  return getMinHeight(columnHeights.value);
};

const increaseColumnHeight = (index: number) => {
  const minHeightColumnIndex = getMinHeightIndex(columnHeights.value);
  columnHeights.value[minHeightColumnIndex] +=
    itemHeights.value[index] + rowSpacing.value;
};
// 计算每个 item 的位置
const useItemPosition = () => {
  const allItems = document.querySelectorAll<HTMLElement>(".item");
  allItems.forEach((item, index) => {
    item.style.left = getItemLeft() + "px";
    item.style.top = getItemTop() + "px";
    increaseColumnHeight(index);
  });
  containerHeight.value = Math.max(...columnHeights.value);
};

onMounted(() => {
  useContainerWidth();
  useColumnWidth();
  targetButton.value = document.getElementById('targetButton');
  targettop.value = document.getElementById('targettop');
});

onBeforeMount(() => {
  // fetchData();
  flush();
});

watch(column, (value) => {
  columnHeights.value = Array(value).fill(0);
  useColumnWidth();
  nextTick(() => {
    useItemHeight();
    useItemPosition();
  });
});

watch(flushdata, (value) => {
  columnHeights.value = Array(column.value).fill(0);
  nextTick(() => {
    useItemHeight();
    useItemPosition();
  });
});

watch([loadstatus, isLoad], (value) => {
  if (!loadstatus.value && isLoad.value) {
    nextTick(() => {
      loadstatus.value = true;
      loadmore();
    });
  }
});

async function fetchData() {
  await get(Api.Img_GetImgPathInfo, params.value)
    .then((response) => {
      if (response.data != null && response.data.rows != null) {
        filedata.value = response.data.rows.filter((re) => re.isfolder);
        imgdata.value = response.data.rows.filter((re) => !re.isfolder);
      }
      data.value = imgdata.value;
      flushdata.value = flushdata.value + 1;
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      message.info(error.name + error.message + error.stack);
    });
}

async function flush() {
  isLoad.value = true;
  data.value = [];
  params.value.currentPage = 1;
}

async function stopload() {
  isLoad.value = false;
}

async function loadmore() {
  params.value.currentPage++;
  console.log("当前加载图片:" + params.value.currentPage);
  await get(Api.Img_GetImgPathInfo, params.value)
    .then((response) => {
      if (response.data != null && response.data.rows != null) {
        filedata.value = response.data.rows.filter((re) => re.isfolder);
        imgdata.value = response.data.rows.filter((re) => !re.isfolder);
      }
      data.value.push(...imgdata.value);
      flushdata.value = flushdata.value + 1;
      loadstatus.value = false;
      if (!imgdata.value || imgdata.value.length <= 0) {
        message.info("已全部加载");
        params.value.currentPage--;
        isLoad.value = false;
      }
      scrollToButton();
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      loadstatus.value = false;
      params.value.currentPage--;
      message.info(error.name + error.message + error.stack);
    });
}

function jump(url) {
  params.value.path = url;
  uploadpath.value = url;
  filename.value = url;
  if (url && url.length > 0) {
    urls.value = params.value.path.split("/");
  } else {
    urls.value = [];
  }
  flush();
}

//回到指定目录
function jumpurl(index) {
  let urlstr = "";
  let t = urls.value.length - 1 - index;
  if (t > 0) {
    for (let i = 0; i < t; i++) {
      urls.value.pop();
    }
  }
  for (let i = 0; i < urls.value.length; i++) {
    if (i <= index) {
      if (urlstr === "") {
        urlstr = urls.value[i];
      } else {
        urlstr = urlstr + "/" + urls.value[i];
      }
    }
  }
  params.value.path = urlstr;
  filename.value = urlstr;
  uploadpath.value = urlstr;
  flush();
}

function addcolumn() {
  if (column.value < 25) {
    column.value++;
  }
}
function removecolumn() {
  if (column.value > 1) {
    column.value--;
  }
}
function submitImgDir(b) {
  if (b) {
    params.value.newname = params.value.name;
    console.log(params.value);
    editImgDirNamePost();
  }
  openimgdir.value = false;
  flush();
}
function submitImg(b) {
  if (b) {
    params.value.newname = params.value.name;
    console.log(params.value);
    editImgNamePost();
  }
  openimg.value = false;
  flush();
}
//删除一个图片
async function delImgPost(item) {
  params.value.name = item.name;
  await post(Api.Img_DelImg, params.value)
    .then((response) => {
      showMessage(response.data, "删除图片");
      flush();
    })
    .catch((error) => {
      console.error(error);
    });
}

//删除一个图片目录
async function delImgDirPost(item) {
  params.value.name = item.name;
  await post(Api.Img_DelImgDir, params.value)
    .then((response) => {
      showMessage(response.data, "删除图片目录");
      flush();
    })
    .catch((error) => {
      console.error(error);
    });
}
//创建一个图片目录
async function addImgDirPost() {
  await post(Api.Img_AddImgDirectory, params.value)
    .then((response) => {
      showMessage(response.data !== "", "添加目录");
      if (response.data !== "") {
        urls.value.push(response.data);
        jumpurl(urls.value.length - 1);
      }
    })
    .catch((error) => {
      console.error(error);
    });
}
function clickImgDir(item) {
  params.value.name = item.name;
  params.value.oldname = item.name;
  imgdirTitle.value = "修改图片目录";
  openimgdir.value = true;
}
//修改图片目录名称
async function editImgDirNamePost() {
  await post(Api.Img_EditImgDirOrName, params.value)
    .then((response) => {
      showMessage(response.data, "修改目录名称");
      flush();
    })
    .catch((error) => {
      console.error(error);
    });
}
function clickImg(item) {
  params.value.name = item.name;
  params.value.oldname = item.name;
  imgTitle.value = "修改图片";
  openimg.value = true;
}
//修改图片名称
async function editImgNamePost() {
  await post(Api.Img_EditImgDirOrName, params.value)
    .then((response) => {
      showMessage(response.data, "修改名称");
      flush();
    })
    .catch((error) => {
      console.error(error);
    });
}
</script>
